﻿using MvvmCross.Core.ViewModels;
using Sidvall.IO;
using Sidvall.UI.Dialogs;
using Sidvall.UI.Entities;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.UI.Wpf.ViewModels
{
    public class FileDialogViewModel : Sidvall.UI.ViewModels.DialogViewModelBase
    {
        #region Public Members

        public Sidvall.IO.StorageManager StorageManager { get; set; }
        public OpenFileDialogContext Context { get; set; }

        #region Title

        private string _Title;
        public string Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }

        #endregion
        #region ActiveFolder

        private Sidvall.UI.Entities.TreeItem _ActiveFolder;
        public Sidvall.UI.Entities.TreeItem ActiveFolder
        {
            get
            {
                return _ActiveFolder;
            }
            set
            {
                _ActiveFolder = value;
                RaisePropertyChanged("ActiveFolder");
            }
        }

        #endregion
        #region ActiveFolderItem

        private Sidvall.UI.Entities.TreeItem _ActiveFolderItem;
        public Sidvall.UI.Entities.TreeItem ActiveFolderItem
        {
            get
            {
                return _ActiveFolderItem;
            }
            set
            {
                _ActiveFolderItem = value;
                RaisePropertyChanged("ActiveFolderItem");
            }
        }

        #endregion
        #region ActiveFolderPath

        public string ActiveFolderPath
        {
            get
            {
                if (this.ActiveFolder == null)
                    return null;
                var item = this.ActiveFolder.DataItem as Sidvall.IO.Folder;
                if (item == null)
                    return null;
                return item.FullName;
            }
        }

        #endregion
        #region Folders

        private Sidvall.UI.Entities.TreeItemCollection _Folders;
        public Sidvall.UI.Entities.TreeItemCollection Folders
        {
            get
            {
                return _Folders;
            }
            set
            {
                _Folders = value;
                RaisePropertyChanged("Folders");
            }
        }

        #endregion
        #region FolderItems

        private Sidvall.UI.Entities.TreeItemCollection _FolderItems;
        public Sidvall.UI.Entities.TreeItemCollection FolderItems
        {
            get
            {
                return _FolderItems;
            }
            set
            {
                _FolderItems = value;
                RaisePropertyChanged("FolderItems");
            }
        }

        #endregion
        #region RootPath

        private string _RootPath;
        public string RootPath
        {
            get
            {
                return _RootPath;
            }
            set
            {
                _RootPath = value;
                RaisePropertyChanged("RootPath");
            }
        }

        #endregion
        #region FileName

        private string _FileName;
        public string FileName
        {
            get
            {
                return _FileName;
            }
            set
            {
                _FileName = value;
                RaisePropertyChanged("FileName");
            }
        }

        #endregion

        // Commands
        #region SelectActiveFolderItemCommand

        public ICommand SelectActiveFolderItemCommand
        {
            get
            {
                return new MvxCommand(async () => await SelectActiveFolderItemAsync());
            }
        }

        #endregion
        #region SelectActiveFolderItemAsync

        public async Task<bool> SelectActiveFolderItemAsync()
        {
            Folder folder;
            File file;

            if (this.ActiveFolderItem == null)
                return false;
            folder = this.ActiveFolderItem.DataItem as Folder;
            if (folder != null)
            {
                await LoadAsync(this.ActiveFolderItem, true, this.ActiveFolderItem);
                return false;
            }
            file = this.ActiveFolderItem.DataItem as File;
            if (file != null)
            {
                this.FileName = file.FullName;
                return await OpenAsync();
            }
            return false;
        }

        #endregion
        #region OpenCommand

        public ICommand OpenCommand
        {
            get
            {
                return new MvxCommand(async () => await OpenAsync());
            }
        }

        #endregion
        #region OpenAsync

        public async Task<bool> OpenAsync()
        {
            string path;

            if (string.IsNullOrWhiteSpace(this.FileName))
                return false;
            path = GetPath(this.ActiveFolderPath, this.FileName);
            var exists = await this.StorageManager.FileExistsAsync(path);
            if (exists)
            {
                this.Context.FileName = path;
                return true;
            }
            else
            {
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowMessageAsync("File Missing", path + " does not exist. Verify that the file name is correct.", MessageType.Information);
                return false;
            }
        }

        #endregion
        #region CancelCommand

        public ICommand CancelCommand
        {
            get
            {
                return new MvxCommand(Cancel);
            }
        }

        #endregion
        #region Cancel

        public void Cancel()
        {
            this.Context.FileName = null;
        }

        #endregion

        #region LoadAsync

        public async Task LoadAsync(TreeItem item, bool loadFolderItems, TreeItem activeFolder)
        {
            TreeItemCollection items;
            Task task;

            if (item == null)
                return;
            if (!this.EventsIsEnabled)
                return;
            task = null;
            using (var busyManager = new Sidvall.Data.BusyManager(this))
            {
                this.EventsIsEnabled = false;
                try
                {
                    if (item.ChildItems.Count == 1)
                    {
                        if (string.IsNullOrWhiteSpace(item.ChildItems[0].Id))
                        {
                            var tmp = this.ActiveFolder;
                            item.ChildItems.Clear();
                            await LoadAsync(item.ChildItems, item.Id);
                            this.ActiveFolder = item;
                        }
                    }
                    if (loadFolderItems)
                    {
                        items = item.ChildItems.Copy();
                        var files = await this.StorageManager.GetFilesAsync(item.Id, null, IO.SearchOption.TopDirectoryOnly, false);
                        items.AddItems(files, item.Id);
                        this.FolderItems = items;
                    }
                    if (activeFolder != null)
                    {
                        var treeItems = Sidvall.UI.Entities.TreeManager.FindRootPath(this.Folders, activeFolder);
                        var ids = (from o in treeItems
                                   select o.Id).ToList();
                        var id = ids.Last();
                        ids.Remove(id);
                        Sidvall.UI.Entities.TreeManager.SetValues(this.Folders, null, true, null, null, null, ids);
                        ids.Clear();
                        ids.Add(id);
                        Sidvall.UI.Entities.TreeManager.SetValues(this.Folders, null, null, true, null, null, ids);
                        this.ActiveFolder = activeFolder;
                    }
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Load Error", ex);
                }
                finally
                {
                    this.EventsIsEnabled = true;
                }
                if (task != null)
                    await task;
            }
        }
        public async Task LoadAsync(TreeItemCollection items)
        {
            await LoadAsync(items, this.RootPath);
        }
        private async Task LoadAsync(TreeItemCollection items, string path)
        {
            if (items == null)
                return;
            var folders = await this.StorageManager.GetFoldersAsync(path, null, IO.SearchOption.TopDirectoryOnly, false);
            items.AddItems(folders, path);
            Sidvall.UI.Entities.TreeManager.SetValues(items, null, null, false, null, null);
            foreach (var item in items)
                item.ChildItems.Add("", "", item.Id, 1, false, null);
        }

        #endregion

        #endregion
        #region Private Members

        private bool EventsIsEnabled { get; set; }

        #region GetPath

        private string GetPath(string rootPath, string path)
        {
            if (string.IsNullOrWhiteSpace(rootPath))
                return path;
            if (string.IsNullOrWhiteSpace(path))
                return rootPath;
            if (System.IO.Path.IsPathRooted(path))
                return path;
            return this.StorageManager.Combine(rootPath, path);
        }

        #endregion

        #endregion
        #region Constructors

        public FileDialogViewModel()
        {
            this.EventsIsEnabled = true;
        }

        #endregion
    }
}
